﻿#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Collections.Generic;

namespace AbstractClass
{
    /// <summary>
    /// Provides a set of static methods to generate a sequence which implements <see cref="IEnumerable{T}"/>
    /// </summary>
    public static class Iterable
    {
        /// <summary>
        /// Generates a sequence of elements of type <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The type of the element in the sequence.</typeparam>
        /// <param name="start">The start element.</param>
        /// <param name="step">The specified step to increment the value in the sequence.</param>
        /// <param name="size">The size of the sequence.</param>
        /// <returns>A sequence of size <paramref name="size"/>.</returns>
        public static IEnumerable<T> Generate<T>(T start, T step, int size)
        {
            return Generate(start, step, size, true);
        }

        /// <summary>
        /// Generates a sequence of elements of type <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The type of the element in the sequence.</typeparam>
        /// <param name="start">The start element.</param>
        /// <param name="step">The specified step to increment the value in the sequence.</param>
        /// <param name="size">The size of the sequence.</param>
        /// <param name="stepUp">if set to <c>true</c> the next element will be incremented specified by <paramref name="step"/>;
        /// otherwise, the next element will be decremented specified by <paramref name="step"/>.</param>
        /// <returns>A sequence of size <paramref name="size"/>.</returns>
        public static IEnumerable<T> Generate<T>(T start, T step, int size, bool stepUp)
        {
            var calculator = new GenericCalculator<T, T, T>();
            return stepUp
                       ? Generate(start, step, size, calculator.Add)
                       : Generate(start, step, size, calculator.Subtract);
        }

        /// <summary>
        /// Generates a sequence of elements of type <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The type of the element in the sequence.</typeparam>
        /// <param name="start">The start element.</param>
        /// <param name="step">The specified step to increment the value in the sequence.</param>
        /// <param name="size">The size of the sequence.</param>
        /// <param name="generator">The function to generate the next element in the sequence.</param>
        /// <returns>A sequence of size <paramref name="size"/></returns>
        public static IEnumerable<T> Generate<T>(T start, T step, int size, Generator<T> generator)
        {
            int count = 1;
            T org = start;
            yield return org;

            while (count < size)
            {
                org = generator.Invoke(org, step);
                count++;
                yield return org;
            }
        }

        /// <summary>
        /// Generates a sequence of elements of type <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The type of the element in the sequence.</typeparam>
        /// <param name="size">The size of the sequence.</param>
        /// <param name="generator">The function to generate the next element in the sequence.</param>
        /// <returns>A sequence of size <paramref name="size"/></returns>
        public static IEnumerable<T> Generate<T>(int size, Func<T> generator)
        {
            int count = 0;
            while (count < size)
            {
                count++;
                yield return generator.Invoke();
            }
        }

        /// <summary>
        /// Generates a sequence from an unknown number of specified values of type <typeparamref name="T"/>.
        /// </summary>
        /// <param name="args">An unknown number of values to generate a sequence.</param>
        /// <returns>A sequence generated from an unknown number of elements.</returns>
        public static IEnumerable<T> Create<T>(params T[] args)
        {
            return args;
        }
    }
}